#include <iostream>

#include <functional>

#include <nemesis.h>

using namespace std;

void print_const (const Recycler<int>& numbers)
{
   string msg;

   const int* c;
   for (Recycler <int>::const_iterator ii = numbers.begin (), maxii = numbers.end (); ii != maxii; ii ++) {
      c = Recycler <int>::data (ii);
      msg = nemesis::functions::asString ("Number 3 (p=0x%x): %d", c, *c);
      Logger::debug (msg, FILE_LOCATION);
   }
}

void debug (const char* str, Recycler<int>::iterator ii)
   throw ()
{
   int* p = Recycler<int>::data (ii);

   string msg (str);
   msg += " (p=";
   msg += functions::asHexString (nemesis_ptrnumber_cast (p));
   msg += functions::asText ("): ", *p);
   Logger::debug (msg, FILE_LOCATION);
}

void run () 
   throw (RuntimeException)
{
   static const int N = 5000;

   Recycler <int> numbers;
   int* p;
   int i;
   string msg;

   // Crear N elementos
   for (i = 0; i < N; i ++) {
      p = numbers.create ();
      *p = i;
   }

   // Los recorre
   for (Recycler <int>::iterator ii = numbers.begin (), maxii = numbers.end (); ii != maxii; ii ++) 
      debug ("Number 1", ii);

   // Calcule cuantos objetos tiene que liberar
   int freeCounter = (rand () % N);
   int number;
   
   Logger::debug (functions::asText ("Nodos a borrar: ", freeCounter), FILE_LOCATION);
   
   while (freeCounter -- > 0) {
      number = rand () % (N * 2);

      for (Recycler <int>::iterator ii = numbers.begin (), maxii = numbers.end (); ii != maxii; ii ++) {
         p = Recycler <int>::data (ii);

         if (*p == number) {
            debug ("Release | ", ii);
            numbers.release (p);
            break;
         }
      }
   }
      
   for (i = 0; i < N; i ++) {
      p = numbers.create ();
      *p = i * 1000;
   }
   for (Recycler <int>::iterator ii = numbers.begin (), maxii = numbers.end (); ii != maxii; ii ++) 
      debug ("Number 2", ii);

   numbers.clear ();
   for (i = 0; i < N; i ++) {
      p = numbers.create ();
      *p = i * 2000;
   }

   print_const (numbers);
}

int main (int argc, const char** argv)
{
   try {
      Logger::setLevel (Logger::Debug); 
      Logger::initialize ("recycler", new TraceWriter ("file.trace", 2048000));
 
      run ();
   }
   catch (Exception& ex) {
      cout << ex.asString () << endl;
   }
   
   return 0;
}
